package com.database;

import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.sql.SQLException;
import java.sql.Connection;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.naming.InitialContext;


/**
 * <p>Title: DSLocator</p>
 * <p>Description: 用singleton模式实现的服务定位器类。<br>
 *    用来得到Connection,并且对DataSource类型的实例进行缓<br>
 *    存。</p>
 * @author kevin
 * @version 1.0
 * @since 2009-6-24
 * @Description  封装了其他的异常。
 */

public class DSLocator extends AbstractLocator {
    //缓存，用来存放查找到的DataSource对象。Map中的key是DataSource的jndi名，value 是DataSource对象。
    private static Map<String,DataSource> dsMap = Collections.synchronizedMap(new HashMap<String,DataSource>());
    //DSLocator的静态变量,经过类的初始化后成为全局的一个实例.
    private static DSLocator dsLocator = new DSLocator();

    private DSLocator() {
    }

    /**
     * 返回dsLocator属性。
     * @return DSLocator - 返回的属性。
     */
    public static DSLocator singleton() {
        return dsLocator;
    }

    /**
     * 用来根据实例的jndi名得到DataSource实例。方法会先在dsMap属性<br>
     * 中查找是否有给实例的缓存。如果有，则用实例生成Connection实例<br>
     * 并返回。如果生成出错，则调用clear方法，然后调用lookup方法找到<br>
     * 该DataSource实例，放入dsMap中，如果缓存中没有该实例，调用lookup方法找到<br>
     * 该DataSource实例，放入dsMap中，调用LogWritter的sysInfo方<br>
     * 法记录存放的实例。
     * @param key:String 实例名
     * @return Connection 得到的Connection
     * @throws NamingException
     * @throws TaxLookupException
     */
    public Connection getInstance(String key){
        if (dsMap.containsKey(key)) { //如果存在于缓存中，返回缓存
//    	if (false) {
            try {
                DataSource ds = dsMap.get(key);
                Connection con = ds.getConnection();
                return con;
            } catch (SQLException ex) { //缓存的内容过期，重新查找
                clear(key);
                Connection con = null;
                try {
                    DataSource ds = (DataSource) lookup(key);
                    dsMap.put(key, ds);
                    con = ds.getConnection();
                } catch (SQLException ex1) {
                	ex1.printStackTrace();
                } catch (NamingException ex1) {
                	ex1.printStackTrace();
                } catch (Exception exOther1) {
                	exOther1.printStackTrace();
                }

                return con;
            }
        } else { //如果不存在于缓存中，查找实例
            Connection con = null;
            try {
                DataSource ds = (DataSource) lookup(key);
                dsMap.put(key, ds);
                con = ds.getConnection();
            } catch (SQLException ex2) {
            	ex2.printStackTrace();
            } catch (NamingException ex2) {
            	ex2.printStackTrace();
            } catch (Exception exOther2) {
            	exOther2.printStackTrace();
            }

            return con;
        }

    }

    /**
     * 抽象类AbstractLocator的getInstance方法的实现。
     * @param name:String 被查找对象的JNDI名
     * @return Object - JNDI得到的对象
     * @throws NamingException
     */
    protected Object lookup(String name) throws NamingException {
        Context ctx = new InitialContext(); //getContext();
        Object obj = ctx.lookup(name);
        return obj;
    }

    /**
     * 清空DSMap属性中的所用缓存实例。然后调用LogWritter的<br>
     * 静态方法sysInfo,在日志中记录缓存已经清空的信息。
     */
    private void clear(String key) {
        if (dsMap.containsKey(key)) {
            dsMap.remove(key);
        }

    }

}
